package edu.arizona.sista.learn.activity.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.arizona.sista.learn.activity.model.PredicateInterval;

public class Utils {
	
	/**
	 * Glue together "close" intervals within a predicate list (method for determining "closeness" still being determined)
	 * @param input Map of the same for as that returned by recognition
	 * @param threshold Threshold to use when glueing
	 * @param glueMethod Glueing heuristic: 1 = glue by density, 2 = glue frames within close proximity
	 * @return A hash map of activity-fluents, where the key is the name of the
	 * activity and the value is a list of predicate-intervals during which
	 * the activity is true.
	 */
	public static Map<String, List<PredicateInterval>> glue(Map<String, List<PredicateInterval>> input,
			double threshold, int glueMethod) {
		Map<String, List<PredicateInterval>> results = new HashMap<String, List<PredicateInterval>>();
		for (String predName : input.keySet()) {
			List<PredicateInterval> curList = input.get(predName);
			
			List<PredicateInterval> gluedList = glue(curList, threshold, glueMethod);
			
			results.put(predName, gluedList);
		}
		return results;
	}
	
	public static List<PredicateInterval> glue(List<PredicateInterval> curList, double threshold, int glueMethod) {
		List<PredicateInterval> gluedList = new ArrayList<PredicateInterval>();
		Map<PredicateInterval, Boolean> skipFrames = new HashMap<PredicateInterval, Boolean>();
		for (int i = 0; i < curList.size(); i++) {
			int j = 0;
			PredicateInterval firstInterval = curList.get(i);
			int gluedStart = firstInterval.start;
			int gluedEnd = firstInterval.end;
			int trueFrames = gluedEnd - gluedStart;
			String pred1 = firstInterval.getPredicate().getArg(0).toString();
			String pred2 = "";
			int numArgs1 = firstInterval.getPredicate().getArgs().length;
			if(numArgs1 > 1) {
				pred2 = firstInterval.getPredicate().getArg(1).toString();
			}
			if(!(skipFrames.containsKey(firstInterval))) {
				boolean cont = true;
				for (j = i+1; j < curList.size() && cont; j++) {
					PredicateInterval curInterval = curList.get(j);
					String pred3 = curInterval.getPredicate().getArg(0).toString();
					String pred4 = "";
					int numArgs2 = curInterval.getPredicate().getArgs().length;
					if(numArgs2 > 1) {
						pred4 = curInterval.getPredicate().getArg(1).toString();
					}
					//System.out.print(pred1+" "+pred3);
					//if(numArgs1 > 1) {System.out.print(" "+pred2);}
					//if(numArgs2 > 1) {System.out.print(" "+pred4);}
					//System.out.print("\n");
					if(numArgs1 == numArgs2 && pred1.equals(pred3) && (numArgs1 == 1  || pred2.equals(pred4))) {
						//System.out.println("matching arguments found");
						int newGluedEnd = curInterval.end;
						int newTrueFrames = trueFrames + curInterval.end - curInterval.start;
						double newRatioTrue = newTrueFrames * 1.0 / (newGluedEnd - gluedStart);
						if ((glueMethod == 1 && newRatioTrue >= threshold)
								|| (glueMethod == 2 && curInterval.start >= gluedEnd && curInterval.start - gluedEnd <= 5)) {
							//System.out.println("Gluing together intervals of "+predName.toString()+": "+Integer.toString(gluedStart)+"-"+Integer.toString(gluedEnd)+" and "+Integer.toString(curInterval.start)+"-"+Integer.toString(newGluedEnd));
							//System.out.println("Arguments: ("+pred1+","+pred2+")"+" ("+pred3+","+pred4+")");
							gluedEnd = newGluedEnd;
							trueFrames = newTrueFrames;
							skipFrames.put(curInterval, true);
						}
						else {
							gluedList.add(new PredicateInterval(curList.get(i).getPredicate().copy(), gluedStart, gluedEnd));
							cont = false;
						}
					}
				}
				if(cont) {
					//System.out.println("FOUND A LONE INTERVAL");
					//System.out.println("Adding "+predName.toString()+": "+Integer.toString(gluedStart)+"-"+Integer.toString(gluedEnd));
					gluedList.add(new PredicateInterval(curList.get(i).getPredicate(), gluedStart, gluedEnd));
				}
			}
		}
		return gluedList;
	}

}
